package com.segersten.kalaha


import java.util.logging.Logger;

import com.segersten.kalaha.domain.EventType
import com.segersten.kalaha.domain.Event
//import java.util.logging.Logger

class GameLogicContainer implements Serializable {

	def get = {GameType type ->
		if (type==GameType.KALAHA) {
			return new KalahaGameLogic()
		}
		return null
 	}
}

class LogicAssert {
	public static assertTrue(boolean check, String msg) { 
		if (!check) {
			throw new IllegalStateException(msg)
		}
 	}
}

class KalahaGameLogic {

	def eventLogicMap = [ (EventType.GAME_CREATED) : new KalahaCreatedLogic(),
					 (EventType.PLAYER_1_JOINED) : new KalahaPlayer1JoinedLogic(),
					 (EventType.PLAYER_2_JOINED) : new KalahaPlayer2JoinedLogic(),
					 (EventType.PLAYER_1_ACTION) : new KalahaPlayer1ActionLogic(),
					 (EventType.PLAYER_2_ACTION) : new KalahaPlayer2ActionLogic(),
					 (EventType.PLAYER_1_TIMEOUT) : new KalahaPlayer1TimeoutLogic(),
					 (EventType.PLAYER_2_TIMEOUT) : new KalahaPlayer2TimeoutLogic(),
					 (EventType.GAME_FINISHED) : new KalahaGameFinishedLogic()]


	def notifyEvent = { Event lastEvent, Event event, Board board -> 
		def logic = eventLogicMap[event.type]
		if (logic) {
			logic.notifyEvent(lastEvent, event, board)
		} else {
			throw new IllegalStateException("Could not dispatch event - reason unknown " + event.type)
		}
	}	
}

class KalahaCreatedLogic {
	def notifyEvent = { Event lastEvent, Event event, Board board -> 
		LogicAssert.assertTrue(lastEvent==null, "First event was not first -> " + lastEvent)
		LogicAssert.assertTrue(board==null, "Board should not have been created yet")
		//return ["nextActor":Actor.ENGINE, "board":new Board(stones:36, buckets:[0,3,3,3,3,3,3,0,3,3,3,3,3,3])];
		return ["nextActor":Actor.ENGINE, "board":new Board(stones:60, buckets:[0,5,5,5,5,5,5,0,5,5,5,5,5,5])];
	}
}

class KalahaPlayer1JoinedLogic {
	def notifyEvent = { Event lastEvent, Event event, Board board -> 
		LogicAssert.assertTrue(board!=null, "Game not started")
		LogicAssert.assertTrue(board.player1==false, "Player 1 has already joined")
		board.player1=true
		return ["nextActor":Actor.ENGINE, "board":board];
	}
}

class KalahaPlayer2JoinedLogic {
	def notifyEvent = { Event lastEvent, Event event, Board board -> 
		LogicAssert.assertTrue(board!=null, "Game not started")
		LogicAssert.assertTrue(board.player2==false, "Player 2 has already joined")	
		board.player2=true
		return ["nextActor":Actor.PLAYER_1, "board":board];
	}
}

class KalahaPlayer1ActionLogic {
	
	def notifyEvent = { Event lastEvent, Event event, Board board -> 

		Logger LOG = Logger.getLogger(KalahaPlayer1ActionLogic.class.getCanonicalName())
		LOG.info("Prestate - ${event.arg}:\n" + board.toString())
		int index = 0
		try {
			index = Integer.parseInt(event.arg)
		} catch(Exception e) { LOG.severe("Exception in ${arg} - " + e); return null }
	
		
		def result = board.move(index, 1, 6)
		def nextActor
		
		boolean gameFinished = false
		if (result.gameFinished==true) {
			nextActor = Actor.NONE
			gameFinished = true
		} else {
		    if (board.buckets[0]+board.buckets[7]==board.stones) {throw new IllegalStateException("Unexpected actor when game was finished " + result) }
			nextActor = result.nextPlayer==true ? Actor.PLAYER_2 : Actor.PLAYER_1
		}
		
		LOG.info("Result " + result)
		LOG.info("Poststate:\n" + board.toString())
		
		return ["nextActor":nextActor, "board":board, "gameFinished":gameFinished]
	}
}

class KalahaPlayer2ActionLogic {
	
	def notifyEvent = { Event lastEvent, Event event, Board board -> 

		int index = 0
		try {
			index = Integer.parseInt(event.arg)
		} catch(Exception e) { LOG.severe("Exception in ${arg} - " + e); return null }
	
		
		def result = board.move(index, 8, 13)
		def nextActor
		
		boolean gameFinished = false
		if (result.gameFinished==true) {
			nextActor = Actor.ENGINE
			gameFinished = true
		} else {
			if (board.buckets[0]+board.buckets[7]==board.stones) {throw new IllegalStateException("Unexpected actor when game was finished " + result) }
			nextActor = result.nextPlayer==true ? Actor.PLAYER_1 : Actor.PLAYER_2
		}
		
		return ["nextActor":nextActor, "board":board, "gameFinished":gameFinished]
	}
}

class KalahaPlayer1TimeoutLogic {
	
	def notifyEvent = { Event lastEvent, Event event, Board board ->
		// TODO check if we're going to do a time out
		LogicAssert.assertTrue(board!=null, "Game not started")
		return ["nextActor":Actor.ENGINE, "board":board, "gameFinished":true]
	}
}

class KalahaPlayer2TimeoutLogic {
	
	def notifyEvent = { Event lastEvent, Event event, Board board ->
		// TODO check if we're going to do a time out
		LogicAssert.assertTrue(board!=null, "Game not started")
		return ["nextActor":Actor.ENGINE, "board":board, "gameFinished":true]
	}
}

class KalahaGameFinishedLogic {
	
	def notifyEvent = { Event lastEvent, Event event, Board board -> 
		LogicAssert.assertTrue(board!=null, "Game not started")
		return ["nextActor":Actor.NONE, "board":board]
	}
}